package com.nan.samsung.qrsan.utils;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * Created by maning on 16/7/27. 生成二维码工具
 */
public class ZXingUtils {

	public static final Map<DecodeHintType, Object> HINTS = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);

	static {
		List<BarcodeFormat> allFormats = new ArrayList<BarcodeFormat>();
		allFormats.add(BarcodeFormat.AZTEC);
		allFormats.add(BarcodeFormat.CODABAR);
		allFormats.add(BarcodeFormat.CODE_39);
		allFormats.add(BarcodeFormat.CODE_93);
		allFormats.add(BarcodeFormat.CODE_128);
		allFormats.add(BarcodeFormat.DATA_MATRIX);
		allFormats.add(BarcodeFormat.EAN_8);
		allFormats.add(BarcodeFormat.EAN_13);
		allFormats.add(BarcodeFormat.ITF);
		allFormats.add(BarcodeFormat.MAXICODE);
		allFormats.add(BarcodeFormat.PDF_417);
		allFormats.add(BarcodeFormat.QR_CODE);
		allFormats.add(BarcodeFormat.RSS_14);
		allFormats.add(BarcodeFormat.RSS_EXPANDED);
		allFormats.add(BarcodeFormat.UPC_A);
		allFormats.add(BarcodeFormat.UPC_E);
		allFormats.add(BarcodeFormat.UPC_EAN_EXTENSION);

		HINTS.put(DecodeHintType.POSSIBLE_FORMATS, allFormats);
		HINTS.put(DecodeHintType.CHARACTER_SET, "utf-8");
	}

	/**
	 * 生成二维码，默认大小为500*500
	 * 
	 * @param text
	 *            需要生成二维码的文字、网址等
	 * @return bitmap
	 */
	public static Bitmap createQRImage(String text) {
		return createQRImage(text, 500);
	}

	// 要转换的地址或字符串,可以是中文
	public static Bitmap createQRImage(String url, int size) {
		Bitmap resultBitmap = null;
		try {
			// 判断URL合法性
			if (url == null || "".equals(url) || url.length() < 1) {
				return null;
			}
			Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
			hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
			hints.put(EncodeHintType.MARGIN, 0); // 边距
			// 图像数据转换，使用了矩阵转换
			BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, size, size, hints);

			int[] pixels = new int[size * size];
			// 下面这里按照二维码的算法，逐个生成二维码的图片，
			// 两个for循环是图片横列扫描的结果
			for (int y = 0; y < size; y++) {
				for (int x = 0; x < size; x++) {
					if (bitMatrix.get(x, y)) {
						pixels[y * size + x] = 0xff000000;
					} else {
						pixels[y * size + x] = 0xffffffff;
					}
				}
			}
			// 生成二维码图片的格式，使用ARGB_8888
			Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
			bitmap.setPixels(pixels, 0, size, 0, 0, size, size);
			resultBitmap = bitmap;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return resultBitmap;
	}

	/**
	 * 生成带logo的二维码，默认二维码的大小为500，logo为二维码的1/5
	 * 
	 * @param text
	 *            需要生成二维码的文字、网址等
	 * @param mBitmap
	 *            logo文件
	 * @return bitmap
	 */
	public static Bitmap createQRCodeWithLogo(String text, Bitmap mBitmap) {
		return createQRCodeWithLogo(text, 500, mBitmap);
	}

	/**
	 * 生成带logo的二维码，logo默认为二维码的1/5
	 * 
	 * @param text
	 *            需要生成二维码的文字、网址等
	 * @param size
	 *            需要生成二维码的大小（）
	 * @param mBitmap
	 *            logo文件
	 * @return bitmap
	 */
	public static Bitmap createQRCodeWithLogo(String text, int size, Bitmap mBitmap) {
		try {
			int IMAGE_HALFWIDTH = size / 10;
			Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
			hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
			hints.put(EncodeHintType.MARGIN, 0); // 边距
			/*
			 * 设置容错级别，默认为ErrorCorrectionLevel.L
			 * 因为中间加入logo所以建议你把容错级别调至H,否则可能会出现识别不了
			 */
			hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

			BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, size, size, hints);

			int width = bitMatrix.getWidth();// 矩阵高度
			int height = bitMatrix.getHeight();// 矩阵宽度
			int halfW = width / 2;
			int halfH = height / 2;

			Matrix m = new Matrix();
			float sx = (float) 2 * IMAGE_HALFWIDTH / mBitmap.getWidth();
			float sy = (float) 2 * IMAGE_HALFWIDTH / mBitmap.getHeight();
			m.setScale(sx, sy);
			// 设置缩放信息
			// 将logo图片按martix设置的信息缩放
			mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), m, false);

			int[] pixels = new int[size * size];
			for (int y = 0; y < size; y++) {
				for (int x = 0; x < size; x++) {
					if (x > halfW - IMAGE_HALFWIDTH && x < halfW + IMAGE_HALFWIDTH && y > halfH - IMAGE_HALFWIDTH
							&& y < halfH + IMAGE_HALFWIDTH) {
						// 该位置用于存放图片信息
						// 记录图片每个像素信息
						pixels[y * width + x] = mBitmap.getPixel(x - halfW + IMAGE_HALFWIDTH, y - halfH
								+ IMAGE_HALFWIDTH);
					} else {
						if (bitMatrix.get(x, y)) {
							pixels[y * size + x] = 0xff000000;
						} else {
							pixels[y * size + x] = 0xffffffff;
						}
					}
				}
			}
			Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
			bitmap.setPixels(pixels, 0, size, 0, 0, size, size);
			return bitmap;
		} catch (WriterException e) {
			e.printStackTrace();
			return null;
		}
	}

	// ------解析图片-----代码来自：https://github.com/bingoogolapple/BGAQRCode-Android----感谢
	/**
	 * 
	 * 同步解析本地图片二维码。该方法是耗时操作，请在子线程中调用。
	 * 
	 * @param picturePath
	 *            要解析的二维码图片本地路径
	 * @return 返回二维码图片里的内容 或 null
	 */
	public static String syncDecodeQRCode(String picturePath) {
		return syncDecodeQRCode(getDecodeAbleBitmap(picturePath));
	}

	/**
	 * 同步解析bitmap二维码。该方法是耗时操作，请在子线程中调用。
	 * 
	 * @param bitmap
	 *            要解析的二维码图片
	 * @return 返回二维码图片里的内容 或 null
	 */
	public static String syncDecodeQRCode(Bitmap bitmap) {
		try {
			int width = bitmap.getWidth();
			int height = bitmap.getHeight();
			int[] pixels = new int[width * height];
			bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
			com.google.zxing.RGBLuminanceSource source = new com.google.zxing.RGBLuminanceSource(width, height, pixels);
			Result result = new MultiFormatReader().decode(new BinaryBitmap(new HybridBinarizer(source)), HINTS);
			if (result != null) {
				return recode(result.getText());
			} else {
				return null;
			}
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 将本地图片文件转换成可解码二维码的 Bitmap
	 * 
	 * @param picturePath
	 *            本地图片文件路径
	 * @return
	 */
	private static Bitmap getDecodeAbleBitmap(String picturePath) {
		try {
			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inJustDecodeBounds = true;
			BitmapFactory.decodeFile(picturePath, options);
			int sampleSize = options.outHeight / 400;
			if (sampleSize <= 0)
				sampleSize = 1;
			options.inSampleSize = sampleSize;
			options.inJustDecodeBounds = false;

			return BitmapFactory.decodeFile(picturePath, options);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 中文乱码
	 * 
	 * @return
	 */
	public static String recode(String str) {
		String formart = "";
		try {
			boolean ISO = Charset.forName("ISO-8859-1").newEncoder().canEncode(str);
			if (ISO) {
				formart = new String(str.getBytes("ISO-8859-1"), "GB2312");
			} else {
				formart = str;
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return formart;
	}

	// ---------
	public static int dip2px(Context context, float dpValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}

}
